
import spinal.core._
import spinal.lib._

object SdioStatus extends SpinalEnum{
    val idle,cmd_init,cmd,rsp_wait,rsp,dat_wait,dat = newElement()
}

case class sdio() extends Component {
    //定义IO
    val io = new Bundle {
      val sdio_clk = out Bool()
      val sdio_cmd = inout(Analog(Bits(1 bits)))
      val sdio_dat = inout(Analog(Bits(4 bits)))

      //
      val sdio_cmd_en   = in Bool()
      val sdio_cmd_valu = in UInt(6 bits)
      val sdio_cmd_argu = in UInt(32 bits)
      val sdio_cmd_need_rsp = in Bool()
      val sdio_rsp      = out Bits(256 bits)

      //分频器
      val sdio_clkdiv   = in SInt(5 bits)

      //数据发送
      val sdio_dat_en       = in Bool()
      val sdio_dat_write    = in Bool()
      val sdio_send_dat     = in Bits(32 bits)
      val sdio_data_len     = in SInt(16 bits)
      val sdio_recv_dat     = out Bits(32 bits)
      val sdio_recv_dat_wr  = out Bool()
    }

    def run(){

        val cmd_remaining = Reg(SInt(8 bits)) init(0)
        val rsp_remaining = Reg(SInt(8 bits)) init(0)
        val cmd_data      = Reg(Bits(48 bits)) init(B(0,48 bits))
        val sdio_cmd_oe   = Reg(Bool()) init(False)
        val sdio_clk      = Reg(Bool()) init(True)
        val rsp_wait      = Reg(Bool()) init(False)
        val rsp           = Reg(Bits(256 bits)) init(B(0,256 bits))
        val clk_cnt       = Reg(SInt(8 bits)) init(0)

        //数据发送
        val send_dat    = Reg(Bits(32 bits)) init(0)
        val dat_remaining    = Reg(SInt(16 bits)) init(0)
        val sdio_dat_oe      = Reg(Bool()) init(False)
        val sdio_dat         = Reg(Bits(4 bits)) init(0)
        val dat_wait         = Reg(Bool()) init(False)
        val recv_dat         = Reg(Bits(32 bits)) init(0)
        val recv_dat_len     = Reg(SInt(5 bits)) init(0)
        val recv_dat_wr      = Reg(Bool()) init(False)
        val recv_crc_len     = Reg(SInt(6 bits)) init(0)
        val recv_crc_0       = Reg(Bits(16 bits)) init(0)
        val recv_crc_1       = Reg(Bits(16 bits)) init(0)
        val recv_crc_2       = Reg(Bits(16 bits)) init(0)
        val recv_crc_3       = Reg(Bits(16 bits)) init(0)
        val status           = Reg(SdioStatus()) init(SdioStatus.idle)
        val cmd_seq          = B"01" ## io.sdio_cmd_valu ## io.sdio_cmd_argu ## B"x01"

        io.sdio_recv_dat_wr := recv_dat_wr
        io.sdio_recv_dat := recv_dat
        io.sdio_clk := sdio_clk;
        io.sdio_rsp := rsp;
        //io.sdio_dat := sdio_dat;

        //cmd_remaining := 5
        //io.sdio_clk := False
        //io.sdio_cmd := False
        when(sdio_cmd_oe ) {
            //当触发发送时
            io.sdio_cmd := cmd_data.resizeLeft(1)
        }

        when(sdio_dat_oe) {
            io.sdio_dat := B"1111"
        }

        // when(
        //     sdio_clk
        // &&  cmd_remaining>0
        // &&  rsp_remaining>0
        // ) {
        //     sdio_clk := False
        // }.otherwise {
        //     sdio_clk := True
        // }

        val transmit = cmd_remaining>0 || rsp_remaining>0 || recv_crc_len>0 || recv_crc_len>0

        //如果在传输状态下,并且clk在低电平时,时钟计数满足分频计数.则拉高电平
        //如果不存在传输,则也会拉高电平
        sdio_clk.riseWhen(((!sdio_clk && transmit) && clk_cnt>=io.sdio_clkdiv) || !transmit)
        sdio_clk.fallWhen(sdio_clk && clk_cnt>=io.sdio_clkdiv)
        //分频计数
        when(clk_cnt<io.sdio_clkdiv){
            clk_cnt := clk_cnt + 1
        }.otherwise {
            clk_cnt := 0
        }

        //接收完成后,往外面发送数据
        recv_dat_wr.riseWhen(recv_dat_len===8 && sdio_clk.rise)
        recv_dat_wr.fallWhen(recv_dat_wr)

        /////////////////////////////////////////////////
        //接收数据
        val recv_dat_flg = (dat_remaining>0) && io.sdio_clk.rise
        when(recv_dat_flg) {
            recv_dat  := recv_dat(31-4 downto 0) ## io.sdio_dat
        }
        //判断接收数据的数量
        when(recv_dat_flg) {
            recv_dat_len  := recv_dat_len + 1
        }
        ///////////////////////////////////////////////////
        //发送数据
        val send_dat_flg = (dat_remaining>0) && io.sdio_clk.rise
        val send_dat_len = Reg(SInt())
        when(send_dat_flg) {
            send_dat  := send_dat(31-4 downto 0) ## B"1111"
        }

        //发送8个数字
        when(send_dat_flg && send_dat_len<8) {
            send_dat_len := send_dat_len + 1
        }.otherwise {
            send_dat_len := 0
        }
        /////////////////////////////////////////////////////////
        //发送命令
        //
        val send_cmd_flg = (cmd_remaining>0) && io.sdio_clk.rise
        sdio_cmd_oe      := send_cmd_flg
        //发送数据
        when(send_cmd_flg) {
            //cmd_data := cmd_data(47-1 downto 0) ## B"1"
        }

        ///////////////////////////////////////////////////////
        //接收应答
        val rsp_recv_flg = (rsp_remaining>0) && io.sdio_clk.rise
        when(rsp_recv_flg) {
            rsp := rsp(254 downto 0) ## io.sdio_cmd
        }
        ////////////////////////////////////////////////////////

        //总处理
        switch(status) {
            is(SdioStatus.idle) {
                when(io.sdio_cmd_en.rise) {
                    status := SdioStatus.cmd_init
                }
            }
            is(SdioStatus.cmd_init) {
                cmd_data    := cmd_seq
                status      := SdioStatus.cmd
            }
            is(SdioStatus.cmd) {

            }
        }


        when(io.sdio_dat_en.rise) {
            //接收数据
            sdio_dat_oe := False
            dat_wait    := True
            dat_remaining   := io.sdio_data_len
        }.elsewhen(dat_wait){
            dat_wait.fallWhen(io.sdio_clk.rise && io.sdio_dat===0)
        }.elsewhen(dat_remaining>0) {
            //接收数据
            when(io.sdio_clk.rise){
                //数据开始接收,位移接收
                dat_remaining := dat_remaining - 1;
            }
            recv_crc_len := 18;
        }.elsewhen(recv_crc_len>0){
            when(io.sdio_clk.rise){
                recv_crc_len := recv_crc_len - 1
                recv_crc_0 := recv_crc_0(15-1 downto 0) ## io.sdio_dat(0)
                recv_crc_1 := recv_crc_1(15-1 downto 0) ## io.sdio_dat(1)
                recv_crc_2 := recv_crc_2(15-1 downto 0) ## io.sdio_dat(2)
                recv_crc_3 := recv_crc_3(15-1 downto 0) ## io.sdio_dat(3)
            }
        }

        when(io.sdio_cmd_en) {
            cmd_remaining   := 48
            cmd_data        := (B"01",io.sdio_cmd_valu,io.sdio_cmd_argu,B"00000000").asBits
        }.elsewhen(cmd_remaining>0) {
            when(io.sdio_clk.rise) {
                cmd_remaining := cmd_remaining - 1
                // cmd_data(47 downto 4)    := cmd_data(47-4 downto 0)
                // cmd_data(3 downto 0)     := B"1111"
                cmd_data    := cmd_data(47-1 downto 0) ## B"1"
            }.otherwise {

            }
            //rsp_remaining := io.sdio_cmd_need_rsp? 48 | 0
            //rsp_remaining := Mux(io.sdio_cmd_need_rsp,48,0)
            when(io.sdio_cmd_need_rsp.rise) {
                rsp_remaining := 48
                rsp_wait      := True
            }.otherwise {
                rsp_remaining := 0
            }
        }.elsewhen(rsp_remaining>0) {

            //已经获得数据
            when(!rsp_wait && io.sdio_clk.rise){
                rsp_remaining := rsp_remaining - 1
            }

            rsp := rsp(255-1 downto 0) ## io.sdio_cmd

            //关闭等待
            when(io.sdio_cmd===0) {
                rsp_wait := False
            }
        }
        .otherwise {
            sdio_cmd_oe     := False
        }

    // when(io.sdio_clk && cmd_remaining>0) {
    //     io.sdio_dat := B"0000"
    // }
    }

    run()
}

object Asdio {
    def main(args:Array[String]){
        SpinalVerilog(new sdio).printPruned()
    }
}


